package cn.silwings.dicti18n.plugin.generate;

import cn.silwings.dicti18n.dict.Dict;
import cn.silwings.dicti18n.plugin.utils.OrderedProperties;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.ResolutionScope;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;

@Mojo(name = "properties", defaultPhase = LifecyclePhase.COMPILE, requiresDependencyResolution = ResolutionScope.COMPILE)
public class GeneratePropertiesMojo extends AbstractDictGeneratorMojo {

    @Override
    void generate(final List<Dict[]> dictsList, final List<String> languages, final File outputDir) throws MojoExecutionException {
        for (final String lang : languages) {
            // <dictName, <code, desc>>
            final String outFileName = String.format("dict_%s.properties", lang);
            final File outFile = outputDir.toPath().resolve(outFileName).toFile();
            final OrderedProperties newDicProps = this.parseDictListToProperties(dictsList);
            final OrderedProperties oldDictProps = this.loadDictFromFile(outFile);
            final OrderedProperties targetDictProps = this.merge(oldDictProps, newDicProps);
            if (!targetDictProps.isEmpty()) {
                this.write(targetDictProps, outFile);
            }
        }
    }

    private void write(final OrderedProperties props, final File outFile) throws MojoExecutionException {
        try (OutputStreamWriter fos = new OutputStreamWriter(Files.newOutputStream(outFile.toPath()), StandardCharsets.UTF_8)) {
            props.store(fos, "Generated by Dict Generator Plugin");
        } catch (IOException e) {
            this.getLog().error("Failed to write properties: " + outFile.getName());
            throw new MojoExecutionException(e);
        }
    }

    private OrderedProperties merge(final OrderedProperties oldDictProperties, final OrderedProperties newDictProperties) {
        final OrderedProperties mergedProperties = new OrderedProperties();
        mergedProperties.putAll(oldDictProperties);

        for (Map.Entry<Object, Object> newEntry : newDictProperties.entrySet()) {
            final Object key = newEntry.getKey();
            final Object value = newEntry.getValue();
            if (!mergedProperties.containsKey(key)) {
                mergedProperties.put(key, value);
            }
        }
        return mergedProperties;
    }

    private OrderedProperties loadDictFromFile(final File outFile) {
        if (!outFile.exists()) {
            return new OrderedProperties();
        }

        final OrderedProperties properties = new OrderedProperties();
        try (InputStreamReader input = new InputStreamReader(Files.newInputStream(outFile.toPath()), StandardCharsets.UTF_8)) {
            properties.load(input);
        } catch (IOException e) {
            this.getLog().warn("Failed to load properties: " + outFile.getName());
            return new OrderedProperties();
        }

        return properties;
    }

    private OrderedProperties parseDictListToProperties(final List<Dict[]> dictArrayList) {
        final OrderedProperties dictProperties = new OrderedProperties();

        dictArrayList.forEach(dictArray -> {
            final String dictName = dictArray[0].dictName();

            for (final Dict dict : dictArray) {
                final String code = StringUtils.defaultIfBlank(dict.code(), "_");
                dictProperties.put(String.format("%s.%s", dictName, code), "");
            }
        });

        return dictProperties;
    }
}